﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using FlaUI.Core.AutomationElements;
using FlaUI.Core.Definitions;
using FlaUI.Core.Exceptions;
using FlaUI.UIA3;
using QQTools.Logging;
using QQTools.Utils;
using static QQTools.Utils.Win32Api;


namespace QQTools.Data.Plus
{
    public static class QQPlus
    {

        /// <summary>
        /// 根据Pid获取QQ
        /// </summary>
        /// <param name="pid"></param>
        /// <returns></returns>
        public static string GetClientSelfUin(int pid)
        {
            LogManager.Info($"[GetClientName] 获取QQ号码被调用  Pid:{pid}");
            // 1. 获取QQ
            IntPtr resultPtr = QQDLL.GetClientSelfUin(pid);
            // 在 C# 中通过 IntPtr 接收返回值，并使用 Marshal.PtrToStringAnsi 转换后立即释放内存（需与易语言约定释放方式）‌
            string qqStr = Marshal.PtrToStringAnsi(resultPtr);
            // return int.Parse(qqStr);
            return qqStr;
        }

        /// <summary>
        /// 根据Pid获取QQ昵称
        /// </summary>
        /// <param name="qq"></param>
        /// <param name="pid"></param>
        /// <returns></returns>
        public static string GetClientName(string qq, int pid)
        {
            LogManager.Info($"[GetClientName] 获取QQ昵称被调用 QQ:{qq} Pid:{pid}");
            // 1. 获取QQ
            IntPtr resultPtr = QQDLL.GetClientName(qq, pid);
            // 在 C# 中通过 IntPtr 接收返回值，并使用 Marshal.PtrToStringAnsi 转换后立即释放内存（需与易语言约定释放方式）‌
            string nickname = Marshal.PtrToStringAnsi(resultPtr);
            return nickname;
        }

        /// <summary>
        /// 根据Pid获取ClientKey
        /// </summary>
        /// <param name="pid"></param>
        /// <returns></returns>
        public static string GetClientKey(int pid)
        {
            // 1. 获取QQ
            IntPtr resultPtr = QQDLL.GetClientKey(pid);
            // 在 C# 中通过 IntPtr 接收返回值，并使用 Marshal.PtrToStringAnsi 转换后立即释放内存（需与易语言约定释放方式）‌
            string clientKey = Marshal.PtrToStringAnsi(resultPtr);
            return clientKey;
        }

        /// <summary>
        /// 判断指定QQ是否在线
        /// </summary>
        /// <param name="Uin"></param>
        /// <param name="Pid"></param>
        /// <returns>true:在线 false:不在线</returns>
        public static bool IsOnline(string Uin, int Pid)
        {
            LogManager.Info($"[IsOnline] 获取QQ:{Uin} Pid:{Pid} 是否在线");
            if (string.IsNullOrEmpty(Uin) || Pid <= 0)
            {
                LogManager.Error($"[IsOnline] 判断QQ:{Uin} PID:{Pid} 是否在线参数错误");
                return false;
            }
            try
            {
                IntPtr resultPtr = QQDLL.IsOnline(Uin, Pid);
                // 在线 resultPtr 0x00000001 离线 resultPtr 0x00000000
                if (resultPtr != IntPtr.Zero)
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                LogManager.Error($"[IsOnline] 判断QQ:{Uin} PID:{Pid} 是否在线异常", ex);
                throw;
            }
            return false;
        }



        /// <summary>
        /// 根据Pid获取群列表
        /// </summary>
        /// <param name="Pid"></param>
        /// <returns></returns>
        public static List<string> GetGroupList(int Pid)
        {
            LogManager.Info($"[GetGroupList] 获取群列表被调用 Pid:{Pid}");
            IntPtr resultPtr = QQDLL.GetGroupList(Pid);
            string groupListStr = Marshal.PtrToStringAnsi(resultPtr);
            List<string> groupList = new List<string>();
            // 使用 ，号进行分割
            if (!string.IsNullOrEmpty(groupListStr))
            {
                groupListStr.Split(',').ToList().ForEach(groupNumber =>
                {
                    if (string.IsNullOrEmpty(groupNumber) == false)
                    {
                        groupList.Add(groupNumber);
                    }
                });
            }

            return groupList;
        }

        /// <summary>
        /// 根据ClentKey获取cookie
        /// </summary>
        /// <param name="qq"></param>
        /// <param name="clientKey"></param>
        /// <returns></returns>
        public static string GetCookieByClentKey(string qq, string clientKey)
        {
            IntPtr resultPtr = QQDLL.GetCookieByClentKey(qq, clientKey);
            return Marshal.PtrToStringAnsi(resultPtr);
        }

        /// <summary>
        /// 根据HttpKey获取cookie
        /// </summary>
        /// <param name="qq"></param>
        /// <param name="httpKey"></param>
        /// <returns></returns>
        public static string GetCookieByHttpKey(string qq, string httpKey)
        {
            IntPtr resultPtr = QQDLL.GetCookieByHttpKey(qq, httpKey);
            return Marshal.PtrToStringAnsi(resultPtr);
        }

        /// <summary>
        /// 获取httpkey
        /// </summary>
        /// <param name="pid"></param>
        /// <returns></returns>
        public static string GetHttpkey(int pid)
        {
            IntPtr resultPtr = QQDLL.GetHttpkey(pid);
            return Marshal.PtrToStringAnsi(resultPtr);
        }


        /// <summary>
        /// 获取QQ号(GetClientSelfUin获取到的QQ如果是负数可以调用这个)
        /// </summary>
        /// <param name="qq"></param>
        /// <returns></returns>
        public static long GetLogInUin(int qq)
        {
            if (qq < 0)
            {
                long qqTmp = 0;
                // 拿 qqLong 和 -2147483648 进行按位与运算 判断结果是不是 -2147483648
                if ((qq & -2147483648) == -2147483648)
                {
                    // 如果是 -2147483648 则取反
                    qqTmp = 2147483648;
                }
                return qqTmp + (qq & 2147483647);
            }
            return qq;
        }


        /// <summary>
        /// 将字符串转换为十六进制表示, 配合 GenerateTencentUrl 使用
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string EncodeToHex(string input)
        {
            var hexBuilder = new StringBuilder();
            foreach (char c in input)
            {
                // 将字符转为两位十六进制（大写）
                hexBuilder.Append(((int)c).ToString("X2"));
            }
            return hexBuilder.ToString();
        }

        /// <summary>
        /// 生成腾讯 WPA 链接, 用于快速唤醒 QQ 群聊窗口或添加群窗口
        /// </summary>
        /// <param name="groupUin">群号</param>
        /// <param name="qqUin">QQ号:用哪个QQ打开窗口</param>
        /// <returns></returns>
        public static string GenerateTencentUrl(long groupUin, string qqUin)
        {
            // 构造 JSON 参数
            var extParam = new { appId = "21" };
            var jsonData = new
            {
                ExtParam = extParam,
                groupUin = groupUin,
                visitor = 1
            };

            // 序列化为 JSON 字符串
            string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(jsonData);

            // 编码为十六进制
            string encodedParam = EncodeToHex(jsonString);

            // 生成最终 URL
            return $"tencent://groupwpa/?subcmd=all&fuin={qqUin}&param={encodedParam}";
        }


        public static int GetQQPid(string qq)
        {
            int pid = 0;
            // 遍历所有窗口(获取标题带有QQ_XXXXX的窗口,拿到QQ)
            EnumWindowsProc callback = (hWnd, lParam) =>
            {
                const int maxLength = 256;
                StringBuilder titleBuilder = new StringBuilder(maxLength);
                GetWindowText(hWnd, titleBuilder, titleBuilder.Capacity);
                string title = titleBuilder.ToString();
                if (title.StartsWith("QQ_" + qq))
                {
                    int tmpPid = GetWindowThreadProcessId(hWnd, out int outPid);
                    pid = outPid;
                    return false; // 结束遍历
                }
                return true; // 继续遍历所有窗口
            };
            EnumWindows(callback, IntPtr.Zero);
            return pid;
        }

        /// <summary>
        /// 检查QQ是否掉线
        /// 当出现 提示 窗口 按钮:立即运行 内容:你需要用号码3377989884运行QQ才能继续。 说明掉线了
        /// </summary>
        public static bool CheckQQIsOffline(string qq)
        {
            try
            {
                using (var automation = new UIA3Automation())
                {
                    IntPtr intPtr = Win32Api.FindWindow("TXGuiFoundation", "提示");
                    if (intPtr == IntPtr.Zero)
                    {
                        LogManager.Warn($"[检查QQ是否掉线] QQ:{qq} 在线");
                        return true;
                    }

                    AutomationElement dialogWindow = automation.FromHandle(intPtr);
                    AutomationElement button = dialogWindow.FindFirstByXPath("//Button[@Name='立即运行']");
                    if (button != null)
                    {
                        LogManager.Info("[检查QQ是否掉线] 找到按钮 立即运行");
                        // 提取掉线的qq号码 你需要用号码3377989884运行QQ才能继续。
                        // FindFirstByXPath 寻找包含 运行QQ才能继续 的文本
                        AutomationElement msgText = dialogWindow.FindFirstByXPath($"//Text[contains(@Name, '{qq}运行QQ才能继续')]");
                        // 关闭掉线窗口
                        FlauiAuto.CloseWindow(dialogWindow);
                        if (msgText != null)
                        {
                            LogManager.Info($"[检查QQ是否掉线]  QQ号码:{qq} 离线");
                        }
                        else
                        {
                            LogManager.Info($"[检查QQ是否掉线]  QQ号码:{qq} 疑似在线");
                        }
                        return false;
                    }
                    else
                    {
                        if (dialogWindow.FindFirstByXPath("//Text[contains(@Name, '你目前处于离线状态')]") != null)
                        {
                            LogManager.Info($"[检查QQ是否掉线]  QQ号码:{qq} 离线");
                            // 关闭掉线窗口
                            FlauiAuto.CloseWindow(dialogWindow);
                            return false;
                        }
                        else
                        {
                            LogManager.Info($"[检查QQ是否掉线]  QQ号码:{qq} 在线");
                            // 关闭掉线窗口
                            FlauiAuto.CloseWindow(dialogWindow);
                            return true;
                        }
                       
                    }
                }
            }
            catch (Exception ex)
            {
                LogManager.Error($"[检查QQ是否掉线] 检查QQ是否掉线失败, 原因:{ex.Message}", ex);
            }
            return false;
        }
        /// <summary>
        /// 从消息字符串中提取5到12位的QQ号码
        /// </summary>
        /// <param name="message">消息字符串</param>
        /// <returns>提取的QQ号码，如果未找到则返回null</returns>
        public static string ExtractQQNumberFromMessage(string message)
        {
            // 使用正则表达式匹配5到12位的数字
            Regex regex = new Regex(@"\d{5,12}");
            Match match = regex.Match(message);

            if (match.Success)
            {
                return match.Value;
            }
            return null;
        }

        /// <summary>
        /// 检查并处理特殊窗口, 如安全提醒窗口或添加群窗口, 返回true表示窗口出现
        /// </summary>
        /// <returns></returns>
        public static bool CheckAndHandleSpecialWindows()
        {
            IntPtr? safetyWindowHandle = GetSafetyReminderWindowHandle();
            if (safetyWindowHandle != null)
            {
                LogManager.Info($"[安全提醒] 找到安全提醒窗口, 群聊被封了");
                Win32Api.CloseWindow(safetyWindowHandle.Value);
                return true;
            }

            IntPtr? addGroupWindowHandle = GetAddGroupWindowHandle();
            if (addGroupWindowHandle != null)
            {
                LogManager.Info($"[添加群窗口]  群聊未加群");
                Win32Api.CloseWindow(addGroupWindowHandle.Value);
                return true;
            }
            return false;
        }
        /// <summary>
        /// 获取安全提醒窗口句柄
        /// </summary>
        /// <returns>成功返回窗口句柄, 失败返回null</returns>
        public static IntPtr? GetSafetyReminderWindowHandle()
        {
            try
            {
                IntPtr intPtr = Utils.Win32Api.FindWindow("TXGuiFoundation", "安全提醒");
                if (intPtr == IntPtr.Zero)
                {
                    LogManager.Warn("[安全提醒] 窗口句柄未找到");
                    return null;
                }
                return intPtr;
            }
            catch (Exception e)
            {
                LogManager.Error($"[安全提醒] 窗口句柄未找到, 原因:{e.Message}");
            }
            return null;
        }
        /// <summary>
        /// 获取添加群窗口句柄
        /// </summary>
        /// <returns>成功返回窗口句柄, 失败返回null</returns>
        public static IntPtr? GetAddGroupWindowHandle()
        {
            try
            {
                IntPtr intPtr = Utils.Win32Api.FindWindow("TXGuiFoundation", "添加群");
                if (intPtr == IntPtr.Zero)
                {
                    LogManager.Warn("[添加群窗口] 窗口句柄未找到");
                    return null;
                }
                return intPtr;
            }
            catch (Exception e)
            {
                LogManager.Error($"[安全提醒] 窗口句柄未找到, 原因:{e.Message}");
            }
            return null;
        }
        /// <summary>
        /// 根据父窗口, 获取邀请进群窗口
        /// </summary>
        public static AutomationElement GetInviteAddGroupWindow(AutomationElement groupChatWindow)
        {

            try
            {
                using (var automation = new UIA3Automation())
                {
                    AutomationElement inviteAddGroupWindow = groupChatWindow.FindFirstDescendant(cf =>
                        cf.ByControlType(ControlType.Window)
                        .And(cf.ByName("邀请进群"))
                    );

                    // AutomationElement inviteAddGroupWindow = automation.FromHandle(hwnd);
                    if (inviteAddGroupWindow == null)
                    {
                        LogManager.Warn("[获取邀请进群窗口] 窗口未找到");
                        return null;
                    }
                    LogManager.Info("[获取邀请进群窗口] 找到窗口");
                    return inviteAddGroupWindow;
                }
            }
            catch (Exception ex)
            {
                LogManager.Error($"[获取邀请进群窗口] 发生异常: {ex.Message}", ex);
                return null;
            }
        }
        public static async Task<AutomationElement> GetGroupChatWindowWin32(int targetProcessId)
        {
            if (targetProcessId == 0)
            {
                LogManager.Error("[GetGroupChatWindowName] 进程ID: 0");
                return null;
            }

            string targetClassName = "TXGuiFoundation"; // 目标窗口类名
            List<IntPtr> matchingWindows = new List<IntPtr>();

            try
            {
                // 枚举窗口并筛选符合条件的窗口
                EnumWindows((hWnd, lParam) =>
                {
                    GetWindowThreadProcessId(hWnd, out int processId);
                    if (processId == targetProcessId)
                    {
                        StringBuilder className = new StringBuilder(256);
                        GetClassName(hWnd, className, className.Capacity);

                        if (className.ToString() == targetClassName)
                        {
                            StringBuilder title = new StringBuilder(256);
                            GetWindowText(hWnd, title, title.Capacity);
                            string windowTitle = title.ToString();

                            if (IsValidWindowTitle(windowTitle))
                            {
                                matchingWindows.Add(hWnd);
                                //  Console.WriteLine($"窗口句柄: {hWnd}, 标题: {windowTitle}");
                            }
                        }
                    }
                    return true; // 继续枚举
                }, IntPtr.Zero);
            }
            catch (Exception ex)
            {
                LogManager.Error($"[枚举窗口] 枚举窗口失败: {ex.Message}");
                return null;
            }

            Console.WriteLine($"找到符合条件的窗口数量: {matchingWindows.Count}");

            if (matchingWindows.Count <= 0)
            {
                LogManager.Error("[获取群聊窗口] 未找到任何符合条件的窗口。");
                return null;
            }

            try
            {
                using (var automation = new UIA3Automation())
                {
                    foreach (var handle in matchingWindows)
                    {
                        AutomationElement groupChatWindow = automation.FromHandle(handle);
                        if (groupChatWindow == null)
                        {
                            Console.WriteLine("窗口未找到");
                            continue;
                        }

                        // 处理群公告窗口，避免群聊主窗口假死
                        if (await HandleGroupAnnouncementWindow(automation, groupChatWindow))
                        {
                            return groupChatWindow;
                        }

                        // 处理“QQ电话”按钮
                        if (IsPhoneButtonAvailable(groupChatWindow))
                        {
                            return groupChatWindow;
                        }
                    }
                }
            }
            catch (InvalidOperationException ex)
            {
                LogManager.Error($"[获取群聊窗口] 操作无效，原因: {ex.Message}");
            }
            catch (ElementNotAvailableException ex)
            {
                LogManager.Error($"[获取群聊窗口] 元素不可用，原因: {ex.Message}");
            }
            catch (Exception e)
            {
                LogManager.Error($"[获取群聊窗口] 获取群聊窗口失败, 原因:{e.Message}, 堆栈: {e.StackTrace}");
            }

            return null;
        }
        // 检查窗口标题是否合法
        private static bool IsValidWindowTitle(string windowTitle)
        {
            return !string.IsNullOrEmpty(windowTitle) &&
                   windowTitle != "腾讯视频" &&
                   windowTitle != "playerShadow" &&
                   windowTitle != "PlayerPluginWnd" &&
                   windowTitle != "我的资料" &&
                   windowTitle != "TXMenuWindow" &&
                   windowTitle != "添加群" &&
                   windowTitle != "QQ";
        }
        // 处理群公告窗口
        private static async Task<bool> HandleGroupAnnouncementWindow(UIA3Automation automation, AutomationElement groupChatWindow)
        {
            try
            {
                var mainWindows = groupChatWindow?.FindAllChildren(cf => cf.ByControlType(ControlType.Window));
                if (mainWindows?.Length > 0)
                {
                    foreach (var window in mainWindows)
                    {
                        // 查找“前往确认”按钮
                        var targetButton = FindTargetButton(window);
                        if (targetButton != null)
                        {
                            LogManager.Info($"[关闭群公告] 找到群聊提示窗口（群名称：{targetButton?.Name}，窗口名称：{targetButton?.Name}）");
                            await Task.Delay(1000);
                            targetButton?.Click();
                            return true; // 返回群聊窗口
                        }
                    }
                }
            }
            catch (ElementNotAvailableException ex)
            {
                LogManager.Error($"[处理群公告] 找到元素失败，原因: {ex.Message}");
            }
            catch (Exception ex)
            {
                LogManager.Error($"[处理群公告] 处理群公告失败，原因: {ex.Message}");
            }

            return false;
        }
        // 查找“前往确认”或“查看详情”按钮
        private static AutomationElement FindTargetButton(AutomationElement window)
        {
            try
            {
                AutomationElement[] targetButton = window?.FindAllDescendants(cf =>
                    cf.ByControlType(ControlType.Button)
                    .And(cf.ByName("前往确认"))
                );

                if (targetButton == null || targetButton.Length == 0)
                {
                    targetButton = window?.FindAllDescendants(cf =>
                        cf.ByControlType(ControlType.Button)
                        .And(cf.ByName("查看详情"))
                    );
                }

                return targetButton?.FirstOrDefault();
            }
            catch (Exception ex)
            {
                LogManager.Error($"[查找按钮] 查找按钮失败，原因: {ex.Message}");
                return null;
            }
        }

        // 检查群聊窗口中是否有“QQ电话”按钮
        private static bool IsPhoneButtonAvailable(AutomationElement groupChatWindow)
        {
            try
            {
                var phoneBtn = groupChatWindow?.FindFirstDescendant(cf =>
                    cf.ByControlType(ControlType.Button)
                    .And(cf.ByName("QQ电话"))
                );
                return phoneBtn != null;
            }
            catch (Exception ex)
            {
                LogManager.Error($"[检查QQ电话按钮] 查找按钮失败，原因: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 辅助方法：查找右键菜单(根据pid查询)
        /// </summary>
        /// <param name="parent"></param>
        /// <returns></returns>
        public static AutomationElement[] FindContextMenu(int processId)
        {
            if (processId < 0)
            {
                LogManager.Error($"[FindContextMenu] Error processId {processId}");
            }
            List<AutomationElement> txGuiWindows = new List<AutomationElement>();

            try
            {
                using (var automation = new UIA3Automation())
                {

                    try
                    {
                        var app = FlaUI.Core.Application.Attach(processId);
                        var mainWindow = app?.GetMainWindow(automation, TimeSpan.FromSeconds(1));

                        if (mainWindow != null &&
                            mainWindow.ControlType == ControlType.Menu &&
                            mainWindow.Name == "TXMenuWindow" &&
                            mainWindow.ClassName == "TXGuiFoundation")
                        {
                            txGuiWindows.Add(mainWindow);
                        }
                    }
                    catch (Exception ex)
                    {
                        // 记录日志或忽略单个进程的错误
                        LogManager.Error($"Error processing process {processId}: {ex.Message}");
                    }

                }
            }
            catch (Exception ex)
            {
                // 捕获全局异常并记录日志
                LogManager.Error($"Global error: {ex.Message}");
            }

            return txGuiWindows.ToArray();
        }

    }
}
